package com.iplant.ams.serviceImpl.dao.ams;

import com.iplant.ams.service.po.ams.AMSPurchaseOrderItem;
import com.iplant.ams.service.po.ams.AMSPurchaseRequestItem;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class AMSPurchaseOrderItemDAO extends BaseDAO {

    private static Logger logger = LoggerFactory.getLogger(AMSPurchaseRequestItemDAO.class);

    private static AMSPurchaseOrderItemDAO Instance = null;

    public static AMSPurchaseOrderItemDAO getInstance() {
        if (Instance == null) {
            Instance = new AMSPurchaseOrderItemDAO();
        }
        return Instance;
    }

    /**
     * 新增或更新
     *
     * @param wLoginUser
     * @param wItem
     * @param wErrorCode
     * @return
     */
    public int Update(BMSEmployee wLoginUser, AMSPurchaseOrderItem wItem, OutResult<Integer> wErrorCode) {
        int wResult = 0;

        try {
            if (wItem == null) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            //如果是从采购申请项创建的采购项，则需更新采购申请项中的已采购数量
            if (wItem.getPurchaseRequestItemID() > 0) {
                // 校验已购数量+采购数量是否大于申请数量
                if (wItem.getPurchasedCount() + wItem.getPurchaseQuantity() > wItem.getRequestQuantity()) {
                    wErrorCode.set(ExceptionTypes.DataInvalid.getValue());
                    return wResult;
                }
                int wUpdateResult = AMSPurchaseRequestItemDAO.getInstance().UpdatePurchaseQuantity(
                        wLoginUser, wItem.getPurchaseRequestItemID(), wItem.getPurchaseQuantity(), wErrorCode);
                if (wErrorCode.Result != 0) {
                    return wResult;
                }
            }

            wItem.setUserInfo(wLoginUser);
            wResult = this.UpdatePo(wLoginUser, wItem, wErrorCode);

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResult;
    }

    /**
     * 收货时回写到货数量，更新到货数量=当前数量+本次到货数
     *
     * @param wLoginUser
     * @param wID
     * @param wReceiveQuantity
     * @param wErrorCode
     * @return
     */
    public int UpdateReceiveQuantity(BMSEmployee wLoginUser, int wID, int wReceiveQuantity, OutResult<Integer> wErrorCode) {
        int wResult = 0;

        try {
            if (wID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            // 查询出采购数量和已到货数量，用于校验本次到货数量
            String wSQL = StringUtils.Format(
                    "SELECT t.* FROM {0}.ams_purchase_order_item t WHERE t.ID = :wID", super.getDBName());
            Map<String, Object> wParamMap = new HashMap<>();
            wParamMap.put("wID", wID);
            wSQL = this.DMLChange(wSQL);
            Pagination wPagination = Pagination.getMaxSize();

            List<AMSPurchaseOrderItem> wItemListTemp = this.QueryForList(wSQL, wParamMap, wPagination, AMSPurchaseOrderItem.class);
            if (wItemListTemp == null || wItemListTemp.isEmpty()) {
                wErrorCode.set(ExceptionTypes.DataInvalid.getValue());
                return wResult;
            }
            AMSPurchaseOrderItem wItemTemp = wItemListTemp.get(0);

            // 校验数量，已到货数量+本次到货数量是否大于采购数量
            if (wItemTemp.getReceiveQuantity() + wReceiveQuantity > wItemTemp.getPurchaseQuantity()) {
                wErrorCode.set(ExceptionTypes.DataInvalid.getValue());
                return wResult;
            }

            wSQL = StringUtils.Format(
                    "UPDATE {0}.ams_purchase_order_item " +
                            " SET ReceiveQuantity = ReceiveQuantity + :wReceiveQuantity " +
                            " WHERE ID = :wID ");

            wParamMap = new HashMap<>();
            wParamMap.put("wID", wID);
            wParamMap.put("wReceiveQuantity", wReceiveQuantity);
            wSQL = this.DMLChange(wSQL);

            this.Update(wSQL, wParamMap);
            wResult = wID;
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResult;
    }

    /**
     * 单条删除
     *
     * @param wLoginUser
     * @param wItem
     * @param wErrorCode
     * @return
     */
    public ServiceResult<Integer> Delete(BMSEmployee wLoginUser, AMSPurchaseOrderItem wItem, OutResult<Integer> wErrorCode) {
        ServiceResult<Integer> wResult = new ServiceResult<Integer>(0);

        try {
            if (wItem == null || wItem.getID() <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            // 判断是否满足删除条件
            // ...


            // 组装SQL语句，先删除采购订单项，如果是从申请单创建的，需要把对应申请项的采购数进行修正
            List<String> wSQLList = new ArrayList<>();

            wSQLList.add(StringUtils.Format(
                    "DELETE FROM {0}.ams_purchase_order_item WHERE ID = {1} ",
                    super.getDBName(), wItem.getID()));

            // 如果是从申请单创建的采购单，需要更新采购项的已采购数量
            if (wItem.getPurchaseRequestItemID() > 0) {
                wSQLList.add(StringUtils.Format(
                        "UPDATE {0}.ams_purchase_request_item SET PurchaseQuantity = PurchaseQuantity - {1} WHERE ID = {2} ",
                        super.getDBName(), wItem.getPurchaseQuantity(), wItem.getPurchaseRequestItemID()));
            }

            int wExecuteResult = super.Execute(wSQLList);
            if (wExecuteResult<0) {
                wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            }
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResult;
    }

    /**
     * 批量删除
     *
     * @param wLoginUser
     * @param wItemList
     * @param wErrorCode
     */
    public ServiceResult<Integer> DeleteList(BMSEmployee wLoginUser, List<AMSPurchaseOrderItem> wItemList, OutResult<Integer> wErrorCode) {
        ServiceResult<Integer> wResult = new ServiceResult<Integer>(0);

        try {
            if (wItemList == null || wItemList.isEmpty()) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            wItemList.removeIf(p -> p.getID() <= 0);
            if (wItemList.isEmpty()) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            // 组装SQL语句，先删除采购项，再更新采购申请项的已采购数量
            List<String> wSQLList = new ArrayList<>();

            // 取出ID队列
            List<Integer> wIDList = wItemList.stream().map(t -> t.getID()).collect(Collectors.toList());
            // 批量删除SQL语句
            wSQLList.add(StringUtils.Format(
                    "DELETE FROM {0}.ams_purchase_order_item WHERE ID in ({1})",
                    super.getDBName(), StringUtils.Join(",", wIDList)));

            // 取出申请单项ID>0的记录，这批记录需要更新对应的采购申请项的已购数量
            List<AMSPurchaseOrderItem> wCleanList = wItemList.stream().filter(t -> t.getPurchaseRequestItemID() > 0).collect(Collectors.toList());
            if (wCleanList != null && (!wCleanList.isEmpty())) {
                // 按照PurchaseRequestItemID分组并求和采购数，用于修改采购申请项的已购数量
                Map<Integer, Integer> wIDCountMap = wCleanList.stream().collect(Collectors.groupingBy(
                        t -> t.getPurchaseRequestItemID(), Collectors.summingInt(t -> t.getPurchaseQuantity())));

                // 剔除掉采购数为0的元素
                wIDCountMap.entrySet().removeIf(t -> t.getValue() <= 0);
                if (!wIDCountMap.isEmpty()) {
                    // 组装SQL语句
                    StringBuilder wStringWhenThen = new StringBuilder();
                    wIDCountMap.forEach((k, v) -> {
                        wStringWhenThen.append(StringUtils.Format(" WHEN {0} THEN {1} ", k, v)) ;
                    });
                    wSQLList.add(StringUtils.Format(
                            "UPDATE {0}.ams_purchase_request_item SET PurchaseQuantity = PurchaseQuantity - CASE ID {1} END WHERE ID in ({2}) ",
                            super.getDBName(), wStringWhenThen.toString(), StringUtils.Join(",", wIDCountMap.keySet())));
                }
            }

            // 批量执行SQL语句，失败则回滚
            int wExecuteResult = super.Execute(wSQLList);
            if (wExecuteResult<0) {
                wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            }
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResult;
    }

    /**
     * 用订单ID查订单货物清单
     *
     * @param wLoginUser
     * @param wOrderID
     * @param wErrorCode
     * @return
     */
    public List<AMSPurchaseOrderItem> SelectListByOrderID(BMSEmployee wLoginUser, int wOrderID, OutResult<Integer> wErrorCode) {
        List<AMSPurchaseOrderItem> wResultList = new ArrayList<>();

        try {
            if (wOrderID <= 0) {
                return wResultList;
            }

            wResultList = this.SelectList(wLoginUser, null, "", "", -1, -1,
                    null, wOrderID, -1, -1,
                    CalendarTool.getBasicDate(), CalendarTool.getBasicDate(), Pagination.getMaxSize(), wErrorCode);
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResultList;
    }

    /**
     * 条件查询集合
     *
     * @param wLoginUser
     * @param wIDs
     * @param wName
     * @param wCode
     * @param wCreatorID
     * @param wActive
     * @param wStateIDList
     * @param wOrderID
     * @param wPurchaseRequestItemID
     * @param wAssetStandardModelID
     * @param wStartTime
     * @param wEndTime
     * @param wPagination
     * @param wErrorCode
     * @return
     */
    public List<AMSPurchaseOrderItem> SelectList(BMSEmployee wLoginUser, List<Integer> wIDs, String wName, String wCode,
            int wCreatorID, int wActive, List<Integer> wStateIDList, int wOrderID, int wPurchaseRequestItemID, int wAssetStandardModelID,
            Calendar wStartTime, Calendar wEndTime, Pagination wPagination, OutResult<Integer> wErrorCode) {
        List<AMSPurchaseOrderItem> wResultList = new ArrayList<>();

        try {
            // ID List
            if (wIDs == null) {
                wIDs = new ArrayList<>();
            }
            wIDs.removeIf(p -> p <= 0);

            // StateID List
            if (wStateIDList == null) {
                wStateIDList = new ArrayList<>();
            }

            // 时间的处理
            Calendar wBaseTime = CalendarTool.getBasicDate();
            wBaseTime.set(2000, 1, 1);
            if (wStartTime == null || wStartTime.compareTo(wBaseTime) < 0) {
                wStartTime = wBaseTime;
            }
            if (wEndTime == null || wEndTime.compareTo(wBaseTime) < 0) {
                wEndTime = wBaseTime;
            }
            if (wStartTime.compareTo(wEndTime) > 0) {
                return wResultList;
            }

            String wSQL = StringUtils.Format(
                    " SELECT t1.*, t2.Name as AssetName, t2.AssetModel as AssetModel, t2.AssetUnit as AssetUnit, " +
                            " t3.RequestQuantity, t3.PurchaseQuantity AS PurchasedCount" +
                            " FROM {0}.ams_purchase_order_item t1 " +
                            " LEFT JOIN {0}.ams_asset_standard_model t2 ON t1.AssetStandardModelID = t2.ID " +
                            " LEFT JOIN {0}.ams_purchase_request_item t3 ON t1.PurchaseRequestItemID = t3.ID " +
                            " WHERE 1=1 " +
                            " AND (:ID = '''' or t1.ID IN (''{1}'')) " +
                            " AND (:Name = '''' OR t1.Name like :Name) " +
                            " AND (:Code = '''' OR t1.Code like :Code) " +
                            " AND (:CreatorID <= 0 OR t1.CreatorID = :CreatorID ) " +
                            " AND (:Active < 0 OR t1.Active = :Active) " +
                            " AND (:Status = '''' OR t1.CurrentStatus IN (''{2}'')) " +
                            " AND (:OrderID <= 0 OR t1.OrderID = :OrderID ) " +
                            " AND (:PurchaseRequestItemID <= 0 OR t1.PurchaseRequestItemID = :PurchaseRequestItemID ) " +
                            " AND (:AssetStandardModelID <= 0 OR t1.AssetStandardModelID = :AssetStandardModelID ) " +
                            " AND (:StartTime <= str_to_date(''2010-01-01'', ''%Y-%m-%d'') OR :StartTime <= t1.CreateTime) " +
                            " AND (:EndTime <= str_to_date(''2010-01-01'', ''%Y-%m-%d'') OR :EndTime >= t1.CreateTime) ",
                    super.getDBName(), StringUtils.Join("','", wIDs), StringUtils.Join("','", wStateIDList));


            Map<String, Object> wParamMap = new HashMap<>();
            wParamMap.put("ID", StringUtils.Join(",", wIDs));
            wParamMap.put("Name", StringUtils.isEmpty(wName) ? "" : ("%" + wName + "%"));
            wParamMap.put("Code", StringUtils.isEmpty(wCode) ? "" : ("%" + wCode + "%"));
            wParamMap.put("CreatorID", wCreatorID);
            wParamMap.put("Active", wActive);
            wParamMap.put("Status", StringUtils.Join(",", wStateIDList));
            wParamMap.put("OrderID", wOrderID);
            wParamMap.put("PurchaseRequestItemID", wPurchaseRequestItemID);
            wParamMap.put("AssetStandardModelID", wAssetStandardModelID);
            wParamMap.put("StartTime", wStartTime);
            wParamMap.put("EndTime", wEndTime);

            wSQL = this.DMLChange(wSQL);

            wResultList = this.QueryForList(wSQL, wParamMap, wPagination, AMSPurchaseOrderItem.class);
        } catch (Exception ex) {
            wErrorCode.set(Integer.valueOf(ExceptionTypes.DBSQL.getValue()));
            logger.error(ex.toString());
        }

        return wResultList;
    }

    /**
     * 幺式注解式条件查询
     *
     * @param wLoginUser
     * @param wParams
     * @param wPagination
     * @param wErrorCode
     * @return
     */
    public List<AMSPurchaseRequestItem> SelectListNew(BMSEmployee wLoginUser,
            Map<String, Object> wParams, Pagination wPagination, OutResult<Integer> wErrorCode) {

        return this.SelectPOList(wLoginUser, wParams, AMSPurchaseRequestItem.class, wPagination, wErrorCode);
    }
}
